#ifndef _UI_SPRITE_H_
#define _UI_SPRITE_H_

#include "graphics/graphics.h"
#include "math/vec2.h"
#include <string>
#include "sprite_set.h"
class Image;
struct AlphaMask;


namespace ui
{

class UIWidget;
class UISprite
{
public:
	enum			ROTATION
	{
		ROTATION_0,
		ROTATION_90,
		ROTATION_180,
		ROTATION_270
	};
					UISprite();
					~UISprite();
					/// automatically calls Tick as well.
	
	void			Setup(  const math::Vec2& Pos, 
							const math::Vec2& Size, 
							float			Rotation = 0.0f,
							float			Scale = 1.0f,
							COLOR			Color = 0xFFFFFFFF);				
	void			FlushImage();
	void			GetScreenSize(math::Vec2& Size, float Scale = 1.0f) const;
	bool			SetTexture();
	bool			Render();
	bool			RenderRotated();
	bool			RenderClipped( const math::Vec2& ClipMin, const math::Vec2& ClipMax );

					/// is point inside the sprite?
	bool				Create(	const std::string& ImageFile, 
								const math::Vec2& UV1 = math::Vec2(0.0f, 0.0f), 
								const math::Vec2& UV2 = math::Vec2(1.0f, 1.0f),
								bool  Additive = false);
	bool				CreateMask();
	void				SetImage(const std::string& ImageFile);
	void				SetImage(const char* ImageData, int DataSize);
	
	
	// returns FALSE is the sprite looped
	bool				Tick(float dt);


	void				FillBuffer(Graphics::Vertex2D* VertA);
	void				FillClippedBuffer(Graphics::Vertex2D* VertA,  const math::Vec2& ClipMin, const math::Vec2& ClipMax );
	void				FillRotBuffer(Graphics::Vertex2D* VertA, float Rot);
	/// accessors
	const math::Vec2&	GetUV1() const { return m_UV1; };
	const math::Vec2&	GetUV2() const { return m_UV2; };
	math::Vec2			GetImageSize() const;
	bool				IsAdditive() const { return m_Additive; };		// is it additive ?
    Image*				GetImage() const { return m_pImage; };
    SpriteInstance*		GetSpriteInst() const { return m_pSpriteInstance; };
	bool				UpdateTime(float& time, float dt) { if (m_pSpriteInstance) return m_pSpriteInstance->UpdateTime(m_LoopC,time, dt, m_Loop); return true; };
	void				ForceAnimTime(float f) { m_Timer  = f; };
	bool				IsInside(const math::Vec2& Pos) const;
	bool				IsInsideMask(const math::Vec2& Pos) const;
	bool				IsInsideMask(UISprite* pSprite) const;
	bool				HasMask() const { return m_pMask ? true : false; }
	float				GetTimer() const { return m_Timer; };

	void				Invalidate();
	bool				IsValid() const { return (m_pImage || m_pSpriteInstance); };
	bool				IsCentered() const { return m_DrawCentered; };
	void				SetCentered(bool b) { m_DrawCentered = b; };
	const std::string&	GetFilename() const { return m_Filename; };

	void				SetPause(bool aPause) { m_Pause = aPause; }
	bool				GetPause() const { return m_Pause; }
	void				SetLoop(bool aLoop) { m_Loop = aLoop; }
	bool				GetLoop() const		{ return m_Loop; }
	void				SetLoopC(int n)		{ m_LoopC = n; }
	int					GetLoopC() const	{ return m_LoopC; }
	int					GetFrame() const;
	float				GetTotalAnimTime()	const;
	void				SetAnimTime(float time);
	void				SetAnimTimeNormalized(float time);
	float				GetAnimTime() const;
	float				GetAnimTimeNormalized() const;
	
	void				UpdateLocalization();

protected:
	bool				IsInsideMask(int x, int y) const;
	// check whether it is already loaded and ready to draw or not, if not ready, make it ready		
	// Automatically called by Tick();
	void				RenderCheck();

public:
							// update
	Image*					m_pImage;
	bool					m_Additive;		//! is it additive ?
	bool					m_DrawCentered;	//! draw with Pos as center, or with Pos as top left?
	math::Vec2				m_UV1, m_UV2;	//! top left and bottom right UVs
	math::Vec2				m_Pos, m_Size, m_SizeOriginal;
	float					m_Rotation;
	bool					m_IsFlipped;	// are the Us flipped?
	COLOR					m_Color;
	std::string				m_Filename;

	// using sprite instance?
	SpriteInstance*			m_pSpriteInstance;
	float					m_Timer;
	ROTATION				m_QuadRotation;

	bool					m_Pause;
	bool					m_Loop;
	int						m_LoopC;

	bool					m_IsLocalized;

	// alpha mask
	AlphaMask*				m_pMask;
	static unsigned char	MASK_ALPHA_TOLERANCE;

	// some global triggers
	static bool				NO_LOAD_IMAGE;
	bool					m_FirstTimeLoaded;
	

};

}  // namespace ui

#endif // _UI_SPRITE_H_